package pira.db.excute;

import java.io.File;
import java.util.ArrayList;
import org.neo4j.graphdb.Node;

import pira.db.ui.GraphDBUI;
import pira.parser.http.CiteSeerX;
import pira.parser.http.PageParser.Article;
import pira.parser.xml.dblp.XMLFilesReader;
import pira.utils.Log;

public class DBScanner {

	// if want to scan a number of node
	public static final long SCANNUMBER = GraphDBUI.ALLNODE;

	// if want to find a number of papers in CiteSeerX
	public static final long PAPERGOAL = GraphDBUI.ALLNODE;

	// change the parameters here to continue a scan
	public static final boolean CONTINUE = false;
	public static final long PAPERALREADYFOUND = 0;
	public static final long TIMEALREADYRUN = 0;

	// scan the database by dividing into small pieces
	public static final int SCANNERID = 1;
	public static final boolean DIVIDED = true;
	public static final int INITIATEINDEX = 0;

	// start and end node ID
	public static final long START_ID = 1;
	public static final long END_ID   = 500;

	// constant for logs
	public static final String STATISTIC = "******Global Analyse******";
	public static final String AUTHORS = "AUTHORS";

	// use to generate log files
	public int[] boundary = { 10, 100, 1000, 2000, 4000, 8000, 16000, 32000,
			64000, 128000, 256000, 512000, 1024000 };
	public int boundaryIndex;
	public Log citedLog;
	public Log referLog;

	// use to calculate the running time
	private long startTime;
	public long sysTime;
	public long dbTime;
	public long requestTime;
	public long allDBTime;
	public long allRequestTime;
	private int[] classification;

	// class CiteSeerX.
	private CiteSeerX csx;

	private Node currentNode;

	// graph database interface
	private GraphDBUI gdbui;

	public DBScanner() {
		gdbui = new GraphDBUI();
		boundaryIndex = INITIATEINDEX;
		if (DIVIDED) {
			File[] list = new File("cited_logs/").listFiles();
			for (File f : list)
				f.delete();
			list = new File("refer_logs/").listFiles();
			for (File f : list)
				f.delete();

			citedLog = new Log("cited_logs/" + SCANNERID + ".log.cited."
					+ boundary[boundaryIndex] + ".txt");
			referLog = new Log("refer_logs/" + SCANNERID + ".log.refer."
					+ boundary[boundaryIndex] + ".txt");
		} else {
			citedLog = new Log("cited_logs/log." + boundary[boundaryIndex]
					+ ".txt", CONTINUE);
			referLog = new Log("refer_logs/log." + boundary[boundaryIndex]
					+ ".txt", CONTINUE);
		}

		startTime = 0;
		classification = new int[8];
		sysTime = 0;
		dbTime = 0;
		requestTime = 0;
		allDBTime = 0;
		allRequestTime = 0;

	}

	public GraphDBUI getGraphDBUI() {
		return this.gdbui;
	}

	public Node getCurrentNode() {
		return this.currentNode;
	}

	private void traversePaper() throws Exception {
		this.startTime = (long) (System.currentTimeMillis() - TIMEALREADYRUN * 1000);
		String str = "Scanner program start at " + startTime + "\n";
		citedLog.write(str);
		System.out.println(str);
		long paperCount = 0;
		long paperFound = PAPERALREADYFOUND;
		long id = START_ID;

		if (CONTINUE) {
			str = " recover at " + System.currentTimeMillis() + "\n";
			citedLog.write(str);
			System.out.println(str);
		}

		if (DIVIDED) {
			str = "====Start Node: " + START_ID + " --------> End Node: "
					+ END_ID + "=======\n";
			citedLog.write(str);
			System.out.print(str);
		}

		while (paperCount < SCANNUMBER && paperFound < PAPERGOAL && id <= END_ID) {
			Node paper = gdbui.getGraphDatabaseService().getNodeById(id);
			if (paper.hasProperty("type")) {
				paperCount++;
				System.out.println("\nThe " + paperCount + "th paper\tID :" + id);
				System.out.println(paper.getProperty("title"));

				currentNode = paper;
				int nType = -1;
				String type = (String) paper.getProperty("type");
				if (type.equals(XMLFilesReader.ARTICLE))
					nType = 0;
				else if (type.equals(XMLFilesReader.INPROCEEDINGS))
					nType = 1;
				else if (type.equals(XMLFilesReader.PROCEEDINGS))
					nType = 2;
				else if (type.equals(XMLFilesReader.BOOK))
					nType = 3;
				else if (type.equals(XMLFilesReader.INCOLLECTION))
					nType = 4;
				else if (type.equals(XMLFilesReader.PHDTHESIS))
					nType = 5;
				else if (type.equals(XMLFilesReader.MASTERSTHESIS))
					nType = 6;
				else if (type.equals(XMLFilesReader.WWW))
					nType = 7;
				System.out.println(type);

				if (!type.equals(GraphDBUI.EXTERNAL)) {
					classification[nType]++;

					String year = (String) paper.getProperty("publish date");
					year = year.substring(0, 4);
					System.out.println(year);

					csx = new CiteSeerX((String) paper.getProperty("title"),
							(String[]) paper.getProperty("authors"), this);
					csx.parse();

					if (csx.getResultNum() > 0) {
						ArrayList<Article> articles = csx.getArticles();
						citedLog.write("\n" + paper.getId() + "\t"
								+ csx.getResultNum() + "\n");
						if (articles != null) {
							System.out.println("Total size is: "
									+ articles.size());
							for (int i = 1; i <= articles.size(); i++) {
								System.out.println(i + " : "
										+ articles.get(i - 1).title);

								// record the title
								citedLog.write(articles.get(i - 1).title + "\n");

								// record the authors
								String[] authors = articles.get(i - 1).authors;
								citedLog.write(AUTHORS);
								for (String author : authors) {
									citedLog.write(":\t" + author);
								}
								citedLog.write("\n");
							}
						} else
							System.out.println(0);
						paperFound++;
					} 

					ArrayList<Article> references = csx.getReferences();
					if (references != null) {
						referLog.write("\n" + paper.getId() + "\t"
								+ references.size() + "\n");

						// record references
						for (Article article : references) {
							// record the title
							referLog.write(article.title + "\n");
							
							// record the year
							referLog.write(article.year + "\n");

							// record the authors
							String[] authors = article.authors;
							referLog.write(AUTHORS);
							for (String author : authors)
								referLog.write(":\t" + author);
							referLog.write("\n");
						}
					}

					allDBTime += dbTime;
					allRequestTime += requestTime;
				}

				if (paperCount == boundary[boundaryIndex]) {
					recordStatistic(paperCount, paperFound);

					// start a new log file
					citedLog.close();
					referLog.close();
					boundaryIndex++;
					if (DIVIDED) {
						citedLog = new Log("cited_logs/" + SCANNERID
								+ ".log.cited." + boundary[boundaryIndex]
								+ ".txt");
						referLog = new Log("refer_logs/" + SCANNERID
								+ ".log.refer." + boundary[boundaryIndex]
								+ ".txt");
					} else {
						citedLog = new Log("cited_logs/log."
								+ boundary[boundaryIndex] + ".txt", CONTINUE);
						referLog = new Log("refer_logs/log."
								+ boundary[boundaryIndex] + ".txt", CONTINUE);
					}
				}
			}
			id++;
		}

		if (paperFound == PAPERGOAL || paperCount == SCANNUMBER || id >= END_ID) {
			recordStatistic(paperCount, paperFound);
		}
	}

	private void recordStatistic(long paperCount, long paperFound) {
		long currentTime = System.currentTimeMillis();
		String s = "\n" + STATISTIC + "\n" + "Parse " + paperCount
				+ " papers.\n" + paperFound + " are found in CiteSeerX.\n"
				+ "After " + (float) (currentTime - startTime) / 1000
				+ " seconds.\n" + "Database time is : "
				+ (float) allDBTime / 1000 + " seconds.\n"
				+ "Request time is : " + (float) allRequestTime / 1000
				+ " seconds.\n" + "Classification:" + XMLFilesReader.ARTICLE
				+ " : " + classification[0] + "\t"
				+ (float) classification[0] / paperCount * 100 + "%\n"
				+ XMLFilesReader.INPROCEEDINGS + " : " + classification[1] + "\t"
				+ (float) classification[1] / paperCount * 100 + "%\n"
				+ XMLFilesReader.PROCEEDINGS + " : " + classification[2] + "\t"
				+ (float) classification[2] / paperCount * 100 + "%\n"
				+ XMLFilesReader.BOOK + " : " + classification[3] + "\t"
				+ (float) classification[3] / paperCount * 100 + "%\n"
				+ XMLFilesReader.INCOLLECTION + " : " + classification[4] + "\t"
				+ (float) classification[4] / paperCount * 100 + "%\n"
				+ XMLFilesReader.PHDTHESIS + " : " + classification[5] + "\t"
				+ (float) classification[5] / paperCount * 100 + "%\n"
				+ XMLFilesReader.MASTERSTHESIS + " : " + classification[6] + "\t"
				+ (float) classification[6] / paperCount * 100 + "%\n"
				+ XMLFilesReader.WWW + " : " + classification[7] + "\t"
				+ (float) classification[7] / paperCount * 100 + "%\n\n";
		citedLog.write(s);
		System.out.println(s);
	}

	private void shutDown() {
		long timePassed = System.currentTimeMillis() - startTime;
		String str = "\nScanner program end after " + (float) timePassed / 1000
				+ "seconds.\n";
		System.out.print(str);
		citedLog.write(str);
		this.citedLog.close();
		this.referLog.close();
		this.gdbui.getGraphDatabaseService().shutdown();
	}

	public static void main(String[] args) throws Exception {

		DBScanner dbscanner = new DBScanner();
		dbscanner.traversePaper();
		dbscanner.shutDown();
	}
}
